package cn.ubest.mvvmcore.base

import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import cn.ubest.mvvmcore.BR
import cn.ubest.mvvmcore.R
import cn.ubest.mvvmcore.bean.ResultState
import cn.ubest.mvvmcore.bean.State
import cn.ubest.mvvmcore.utils.DoubleClickHelper
import cn.ubest.mvvmcore.utils.ToastUtils
import cn.ubest.mvvmcore.widget.LoadingDialog
import com.gyf.barlibrary.ImmersionBar
import java.lang.reflect.ParameterizedType

/**
 * Created by maoqi on 2020/9/22.
 */
abstract class BaseActivity<VM : BaseViewModel<*>, B : ViewDataBinding> :
    AppCompatActivity() {
    val mViewModel: VM by lazy {
        val parameterizedType = javaClass.genericSuperclass as ParameterizedType
        val cla = parameterizedType.actualTypeArguments[0] as Class<VM>
        ViewModelProvider(this).get(cla)
    }

    val mBinding: B by lazy {
        DataBindingUtil.setContentView<B>(this, initLayout())
    }
    private val mLoadingDialog: LoadingDialog by lazy {
        LoadingDialog.newInstance()
    }

    abstract fun initLayout(): Int

    /**
     * 生命周期开始,在initView之前调用，主要用于初始化数据
     */
    abstract fun initData(intent: Intent)

    /**
     * initData之后调用，主要是初始化View
     */
    abstract fun initView()

    /**
     * initView之后调用，在这里可以用ViewModel请求网络数据
     */
    abstract fun loadData()

    /**
     * databinding的VariableId，一般是绑定viewmodel，如果不使用则返回null
     */
    open fun getVariableId(): Int? {
        return if (mViewModel is SimpleViewModel) {
            null
        } else {
            BR.vm
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding.lifecycleOwner = this
        lifecycle.addObserver(mViewModel)
        getVariableId()?.also {
            mBinding.setVariable(it, mViewModel)
        }
        //这里监听一些通用操作，比如关闭Activity
        mViewModel.mOperatingLiveData.observe(this, Observer {
            when (it) {
                BaseViewModel.FINISH_ACTIVITY -> finish()
            }
        })
        //这里监听loading状态的更改
        mViewModel.mLoadStatusLiveData.observe(this, Observer {
            when (it.state) {
                State.LOADING_START -> startLoading(it.isInit)
                State.LOADING_END -> stopLoading()
                State.LOADING_FAILED -> {
                    loadFailed(it.code, it.message)
                }
            }
        })
        initStatusBar()
        initData(intent)
        initToolbar()
        initView()
        loadData()
    }

    protected var mTbToolbar: Toolbar? = null
    protected var mTvToolbarTitle: TextView? = null
    protected var mFlToolbar: FrameLayout? = null

    protected open fun initToolbar() {
        mTbToolbar = findViewById(R.id.tb_toolbar)
        mTvToolbarTitle = findViewById(R.id.tv_toolbar_title)
        mFlToolbar = findViewById(R.id.fl_toolbar)
        mTbToolbar?.also {
            setSupportActionBar(mTbToolbar)
            val actionBar = supportActionBar
            actionBar?.setDisplayHomeAsUpEnabled(showBackIcon())
            actionBar?.setDisplayShowHomeEnabled(showBackIcon())
            actionBar?.setDisplayShowTitleEnabled(false)
        }
        mTvToolbarTitle?.also {
            it.text = setToolbarTitle()
        }
    }

    /**
     * 设置toolbar的标题
     *
     * @return
     */
    protected open fun setToolbarTitle(): String? {
        return ""
    }

    /**
     * 是否需要显示toolbar上的返回按钮，默认显示
     *
     * @return
     */
    protected open fun showBackIcon(): Boolean {
        return true
    }

    open fun initStatusBar() {
        //深色状态栏文字
        ImmersionBar.with(this).statusBarDarkFont(true).init()
    }

    open fun startLoading(isInit: Boolean) {
        if (!mLoadingDialog.isAdded) {
            addFragment(mLoadingDialog)
        }
    }

    open fun stopLoading() {
        if (mLoadingDialog.isAdded) {
            removeFragment(mLoadingDialog)
        }
    }

    open fun loadFailed(code: Int?, message: String?) {
        message?.also {
            ToastUtils.toast(it)
        }
    }

    protected fun addFragment(
        @IdRes contentViewId: Int,
        fragment: Fragment
    ) {
        try {
            if (contentViewId == -1) {
                if (!fragment.isAdded) {
                    supportFragmentManager.beginTransaction()
                        .remove(fragment)
                        .add(fragment, fragment.javaClass.simpleName)
                        .commitAllowingStateLoss()
                }
            } else {
                supportFragmentManager.beginTransaction()
                    .replace(contentViewId, fragment, fragment.javaClass.simpleName)
                    .commitAllowingStateLoss()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun addFragment(fragment: Fragment) {
        addFragment(-1, fragment)
    }

    fun removeFragment(fragment: Fragment) {
        supportFragmentManager.beginTransaction().remove(fragment).commitAllowingStateLoss()
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        return super.onCreateOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (DoubleClickHelper.isOnDoubleClick()) {
            return super.onOptionsItemSelected(item)
        }
        when (item.itemId) {
            android.R.id.home -> onBackPressed()
        }
        return super.onOptionsItemSelected(item)
    }

    protected fun <T> getObserver(onSuccess: (t: T) -> Unit): Observer<ResultState<T>> {
        return Observer {
            when (it) {
                is ResultState.Start -> startLoading(it.isInit)
                is ResultState.Response -> onSuccess(it.response)
                is ResultState.Finally -> stopLoading()
                is ResultState.Error -> loadFailed(it.code, it.message)
            }
        }
    }

    protected fun getDoubleClickListener(click: (view: View?) -> Unit): DoubleClickHelper.OnClickListener {
        return object : DoubleClickHelper.OnClickListener() {
            override fun onClicked(view: View?) {
                click(view)
            }

        }
    }
}